#pragma once
#include<iostream>
#include<string>
#include<strings.h>
#include<vector>
#include<memory>
#include<sstream>
#include<fstream>
#include<functional>
#include<unordered_map>

#include"Log.hpp"

static const std::string sep = "\r\n";
static const std::string header_sep = ": ";
static const std::string wwwroot = "wwwroot";
static const std::string homepage="index.html";
static const std::string httpversion = "HTTP/1.0";
static const std::string space = " ";
static const std::string filesuffixsep = ".";//文件后缀分隔符
static const std::string args_sep = "?";
class HttpRequest;
class HttpResponse;
using func_t = std::function<std::shared_ptr<HttpResponse>(std::shared_ptr<HttpRequest>)>;

//http内部要根据目标套访问的资源的文件后缀，区分清楚文件类型，通过Content-Type告诉浏览器，response的正文的类型
class HttpRequest
{
    private:
    //\r\n正文
    std::string GetOneline(std::string &reqstr)
    {
        if(reqstr.empty())
        {
            return reqstr;
        }
        auto pos = reqstr.find(sep);
        if(pos==std::string::npos)
        {
            return std::string ();
        }
        std::string line = reqstr.substr(0,pos);
        reqstr.erase(0,pos+sep.size());
        return line.empty()?sep:line;
    }
    //解析报头
    bool ParseHeaderHelper(const std::string &line,std::string *k,std::string *v)
    {
        auto pos =line.find(header_sep);
        if(pos ==std::string::npos)
        {
            return false;
        }
        *k = line.substr(0,pos);
        *v = line.substr(pos+header_sep.size());
        return true;
    }
    public:
        HttpRequest()
        :_blank_line(sep)
        ,_path(wwwroot)
        {}
        void Serialize()
        {

        }
        void Derialize(std::string &reqstr)
        {
            _req_line = GetOneline(reqstr);
            while (true)
            {
               std::string line = GetOneline(reqstr);
               if(line.empty())
               {
                break;
               }
               else if(line ==sep)
               {
                _req_text = reqstr;//文本
                break;
               }
               else
               {
                _req_header.emplace_back(line);//行
               }
            }
            ParseReqLine();//解析请求行
            ParseHeader();//解析多个报头
           
        }
        void Print()
        {
            std::cout<<"=="<<_req_line<<std::endl;
            for (auto &header : _req_header)
            {
                std::cout<<"***"<<header<<std::endl;
            }
            std::cout<<_blank_line;//空行
            std::cout<<_req_text<<std::endl;//正文

            std::cout<<"method ### "<<_method<<std::endl;
            std::cout<<"url ### "<<_url<<std::endl;
            
            std::cout<<"path ### "<<_path<<std::endl;//路径
            std::cout<<"httpverion ###"<<_version<<std::endl;
            for(auto &header:_headers)
            {
                std::cout<<"@@@"<<header.first<<"-"<<header.second<<std::endl;
            }
        }
        bool ParseReqLine()//解析请求行
        {
            if(_req_line.empty())
            {
                return false;
            }
            std::stringstream ss(_req_line);
            ss>>_method>>_url>>_version;

            if(strcasecmp("get",_method.c_str())==0)
            {
                auto pos = _url.find (args_sep);
                if(pos ==std::string::npos)
                {
                    LOG(INFO,"change being url:%s\n",_url.c_str());
                    _args = _url.substr(pos+args_sep.size());
                    _url.resize(pos);
                    LOG(INFO,"change done url:%s,_args:%s\n",_url.c_str(),_args.c_str());
                }
            }
            _path += _url;
            
            LOG(DEBUG,"url:%s\n",_url.c_str());
            //判断是不是请求根目录/---wwwroot/
            if(_path[_path.size()-1]=='/')
            {
                _path+=homepage;
            }
            auto pos = _path.find(filesuffixsep);//filesuffixsep文件后缀分隔符
            if(pos ==std::string::npos)
            {
                _suffix = ".unlnown";
            }
            else
            {
                _suffix = _path.substr(pos);
            }
            LOG(INFO,"client wang get %s,_suffix:%s\n",_path.c_str(),_suffix.c_str());
            return true;
        }
        bool ParseHeader()
        {
            for(auto &header:_req_header)
            {
                std::string k,v;
                if(ParseHeaderHelper(header,&k,&v));//解析报头
                {
                    _headers.insert(std::make_pair(k,v));
                }
            }
            return true;
        }
        std::string Path()
        {
            return _path;
        }
        std::string Suffix()
        {
            return _suffix;
        }
        bool IsExec()
        {
            return !_args.empty()||!_req_header.empty();
        }
        std::string Args()
        {
            return _args;
        }
        std::string Text()
        {
            return _req_text;
        }
        std::string Method()
        {
            return _method;
        }
        ~HttpRequest()
        {}
    private:
    //原始协议内容
    std::string _req_line;
    std::vector<std::string> _req_header;//报头
    std::string _blank_line;//空白行
    std::string _req_text;//正文
    //解析的结果
    std::string _method;//方法
    std::string _url;//定位符
    std::string _args;
    std::string _path;//路径
    std::string _suffix;//后缀
    std::string _version;//版本号
    std::unordered_map<std::string,std::string> _headers;
};

class HttpResponse
{
    public:
    HttpResponse()
    :_version(httpversion)
    ,_blank_line(sep)
    {}
    void AddStatusline(int code,const std::string &desc)//状态行
    {
        _code = code;
        _desc = desc;//描述符
    }
    void AddHeader(const std::string &k,const std::string &v)
    {
        LOG(DEBUG,"AddHeader:%s->%s\n",k.c_str(),v.c_str());
        _headers[k] = v;
    }
    void AddText(const std::string &text)//正文
    {
        _resp_text = text;
    }
    std::string Serialize()//序列化
    {
        std::string _status_line = _version+space+std::to_string(_code)+space+_desc+sep;
        for(auto &header:_headers)
        {
            _resp_header.emplace_back(header.first+header_sep+header.second+sep);
        }
        //序列化
        std::string respstr = _status_line;
        for(auto &header:_resp_header)
        {
            respstr +=header;
        }
        respstr+=_blank_line;
        respstr+=_resp_text;
        return respstr;
    }
    ~HttpResponse()
    {}
    private:
    //构建应答的字段
    std::string _version;//版本号
    int _code;
    std::string _desc;//描述
    std::unordered_map<std::string,std::string> _headers;//头部信息(报头)

    //应答的结构化字段
    std::string _status_line;//状态行
    std::vector<std::string> _resp_header;
    std::string _blank_line;//空行
    std::string _resp_text;//正文
};

class Factory
{
public:
    static std::shared_ptr<HttpRequest> BuildHttpRequest()
    {
        return std::make_shared<HttpRequest>();
    }
    static std::shared_ptr<HttpResponse>BuildHttpResponose()
    {
        return std::make_shared<HttpResponse>();
    }
};

class HttpServer
{
    public:
    HttpServer()
    {
        //后缀
        _mime_type.insert(std::make_pair(".html","text/html"));
        _mime_type.insert(std::make_pair(".css","text/css"));
        _mime_type.insert(std::make_pair(".js","application/x0javascript"));
        _mime_type.insert(std::make_pair(".png","text/png"));
        _mime_type.insert(std::make_pair(".jpg","text/jpg"));
        _mime_type.insert(std::make_pair(".unknown","text/html"));
        //状态码网站
        _code_to_desc.insert(std::make_pair(100,"Continue"));//	继续。客户端应继续其请求
        _code_to_desc.insert(std::make_pair(200,"OK"));//请求成功。一般用于GET与POST请求
        _code_to_desc.insert(std::make_pair(301,"Moved Permanently"));//永久移动。请求的资源已被永久的移动到新URI，
        //返回信息会包括新的URI，浏览器会自动定向到新URI。
        //。今后任何新的请求都应使用新的URI代替
        _code_to_desc.insert(std::make_pair(302,"Found"));//临时移动。与301类似。但资源只是临时被移动。客户端应继续使用原有URI
        _code_to_desc.insert(std::make_pair(404,"Not Found"));//服务器无法根据客户端的请求找到资源（网页
        //通过此代码，网站设计人员可设置"您所请求的资源无法找到"的个性页面
        _code_to_desc.insert(std::make_pair(500,"Internal Server Error"));//服务器内部错误，无法完成请求
    }
    void AddHandle(const std::string funtionname,func_t f)
    {
        std::string key = wwwroot+funtionname;//wwwroot/login登入
        _funcs[key] = f;
    }
    std::string ReadFileContent(const std::string &path,int *size)//读取文件内容
    {
        //要按照二进制打开
        std::ifstream in(path,std::ios::binary);
        if(!in.is_open())
        {
            return std::string();
        }
        in.seekg(0,in.end);//可用于将信息 （放入 写入）到文件中将指针移动到末尾
        int filesize = in.tellg();//获取当前指针位置和文件大小
        in.seekg(0,in.beg);//将指针移动到文件头部(开头
        
        std::string content;
        content.resize(filesize);
        in.read((char *)content.c_str(),filesize);//读取
        in.close();
        *size = filesize;
        return content;
    }

    std::string handlerHttpReqeust(std::string req)//处理请求
    {
#ifdef TEST
        std::cout<<"------------------------------------"<<std::endl;
        std::cout<<req;

        //客户端的http
        std::string response = "HTTP/1.0 200 OK\r\n";//应答
        response+="\r\n";//
        response+="<html><body><h1>hello world, hello bite!</h1></body></html>"//网站内容
        return response;

#else
        std::cout<<"------------------------------------"<<std::endl;
        std::cout<<req;

        auto request = Factory::BuildHttpRequest();
        request->Derialize(req);

        if(request->IsExec())
        {
            auto response =_funcs[request->Path()](request);
            response->Serialize();
        }
        else
        {
            auto resopnse = Factory::BuildHttpResponose();
            int  code = 200;
            int contentsize = 0;
            std::string text = ReadFileContent(request->Path(),&contentsize);
            if(text.empty())
            {
                code = 404;
                resopnse->AddStatusline(code,_code_to_desc[code]);
                std::string text404 = ReadFileContent("wwwroot/404.html",&contentsize);
                resopnse->AddHeader("Content-Length",std::to_string(contentsize));
                resopnse->AddHeader("Content-Type",_mime_type[".html"]);
                resopnse->AddText(text404);
            }
            else
            {
                std::string suffix = request->Suffix();
                resopnse->AddStatusline(code,_code_to_desc[code]);
                resopnse->AddHeader("Conten-Length",std::to_string(contentsize));
                resopnse->AddText(text);
                resopnse->AddHeader("Conten-type",_mime_type[suffix]);
            }
            return resopnse->Serialize();
        }
#endif
    }
    
    ~HttpServer()
    {}
    private:
    std::unordered_map<std::string,std::string> _mime_type;
    std::unordered_map<int,std::string> _code_to_desc;//描述符
    std::unordered_map<std::string,func_t> _funcs;
};
